Skip to content

fix: win condition on frag + suicide#74

Merged
ec- merged 2 commits into
ec-:masterfrom
WofWca:fix-check-exit-rules-order
May 30, 2026
Merged

fix: win condition on frag + suicide#74
ec- merged 2 commits into
ec-:masterfrom
WofWca:fix-check-exit-rules-order

Conversation

@WofWca
Copy link
Copy Markdown
Contributor

@WofWca WofWca commented May 22, 2026

This is the inconsistent behavior in question:

splash-damage-win-inconsistency.mp4

With the fix:

fix-win-condition-last-frag.mp4

And this is how we handle the "fragged each other at the same time" situation:

tied-new-1-render.mp4
log

Reproducible with bind Y "set g_speed 1; set bot_pause 0; +fire", and com_maxfps 30; sv_fps 20. (Another useful bind: bind U "toggle bot_pause").

]\toggle g_speed 320 1
Server: g_speed changed to 1
t=224450 fire_rocket, owner: Keel
t=224450 G_RunMissile 0, owner: Keel
t=224450 fire_rocket, owner: WofWca
t=224500 G_RunMissile 0, owner: Keel
t=224500 G_RunMissile 1, owner: WofWca
t=224550 G_RunMissile 0, owner: Keel
t=224550 G_RunMissile 1, owner: WofWca
t=224600 G_RunMissile 0, owner: Keel
t=224600 G_RunMissile 1, owner: WofWca
t=224650 G_RunMissile 0, owner: Keel
t=224650 G_RunMissile 1, owner: WofWca
t=224700 G_RunMissile 0, owner: Keel
t=224700 G_RunMissile 1, owner: WofWca
t=224750 G_RunMissile 0, owner: Keel
t=224750 G_RunMissile 1, owner: WofWca
WofWca^7 ate Keel^7's rocket
Keel^7 ate WofWca^7's rocket
]\stoprecord 
Stopped demo recording.

(if you're wondering about the "teams are tied" announcement:
it's not about this MR. It's also reproducible in vanilla,
if you shoot first a teammate then an enemy with the railgun).

Compared to #73
this is a more general and robust fix,
also affecting railgun, shotgun, direct missile hits,
and telefrags.
Basically this ensures that weapon behavior does not differ
depending on whether there is 1 frag left or not.
That is, a railgun kills two players if they're aligned,
a rocket kills everyone who's in splash radius, etc.

I actually started working on this before #73 got merged,
but unfortunately I didn't mark it as draft in time.
So when/if this MR gets merged, that one
is basically not needed anymore and can be reverted for simplicity.
Or maybe the consistency is nice anyway,
at least for the order of log messages,
so only the comment needs to be adjusted at least.

Note that G_RunFrame still calls CheckExitRules() directly,
which probably makes sense, to keep things as is there.

Related:

@WofWca WofWca force-pushed the fix-check-exit-rules-order branch from cdb7ca1 to 9cbf4e6 Compare May 22, 2026 17:44
ec-
ec- previously requested changes May 22, 2026
Copy link
Copy Markdown
Owner

@ec- ec- left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, NEVER change physical location of vmMain(): it MUST be the very first function compiled into the .qvm file as it said in original comment.
Use proper forward declarations instead.

@WofWca WofWca force-pushed the fix-check-exit-rules-order branch from 9cbf4e6 to da78b0e Compare May 22, 2026 19:10
@WofWca
Copy link
Copy Markdown
Contributor Author

WofWca commented May 22, 2026

I missed that, good point. Fixed now I think.

@ec-
Copy link
Copy Markdown
Owner

ec- commented May 22, 2026

Sorry, I miss the point for a moment, but also, please avoid such things in general: f8582a1
q3lcc literally does nothing for inlining so you're just adding another abstraction layer/runtime overhead (+1 function call) for QVM, it may work for DLLs but will not work for QVMs, degrading its performance

@WofWca
Copy link
Copy Markdown
Contributor Author

WofWca commented May 22, 2026

q3lcc literally does nothing for inlining

I didn't know that, interesting.
Do you have a simple suggestion in mind how we can avoid an extra call here, without having to care for each return in RunCommand?

@WofWca
Copy link
Copy Markdown
Contributor Author

WofWca commented May 22, 2026

Ah, I think I can just make the function have 1 return. I'll do that tomorrow.

@ensiform
Copy link
Copy Markdown

Personally I don't think you're saving any real measurable difference with adding the run command extra function call over having the switch. Even in qvm compared to native there will be very little improvement

@WofWca WofWca force-pushed the fix-check-exit-rules-order branch from da78b0e to 37916aa Compare May 23, 2026 07:24
@WofWca
Copy link
Copy Markdown
Contributor Author

WofWca commented May 23, 2026

Sorry, @ensiform I'm not sure what you mean? Regarding returns I'm more concerned with maintainability / readability. Please see if the new version clarifies it.

@ensiform
Copy link
Copy Markdown

This refactor doesn't really belong in the same pr as the other change IMHO. What does this change actually add?

@WofWca
Copy link
Copy Markdown
Contributor Author

WofWca commented May 24, 2026

This refactor doesn't really belong in the same pr as the other change IMHO

How would I ensure to do if (level.needToCheckExitRules) CheckExitRules(); at the end of every vmMain() then? That's the point of the refactor.

@WofWca WofWca force-pushed the fix-check-exit-rules-order branch from 37916aa to d4956d3 Compare May 24, 2026 14:11
@ensiform
Copy link
Copy Markdown

ensiform commented May 24, 2026

Why does that suddenly need to be called at the end of the vmmain?

CheckExitRules typically runs on per frame basis. Calling it whenever vmMain is invoked for one of the limited vm_calls seems extremely unnecessary as opposed to during runframe already because that's the only one which fires often. I don't see how it fixes the problem when you're just calling it multiple times per frame then.

@WofWca
Copy link
Copy Markdown
Contributor Author

WofWca commented May 24, 2026

In vanilla (and current main) CheckExitRules runs not only at the end of the frame but also in ClientThink_real and IIRC RunMissile, after each individual frag, which there can be several of per single shot.
This MR makes it not run after each frag but instead runs it at the end of each command (event/frame).

Perhaps I'll need to adjust commit message to clarify this.
Look at the video and notice that I don't die. Only Crash dies. This is the bug.

@ensiform
Copy link
Copy Markdown

I'm confused because you already fixed that in the other commit allegedly from etlegacy similar message?

@WofWca
Copy link
Copy Markdown
Contributor Author

WofWca commented May 24, 2026

Yes, I submitted that first but then came up with this supposedly better solution, which also fixes the bug for the railgun, the shotgun and everything. See MR description.
Edit: and it fixes the still remaining missile bug where during sudden death we'd kill self (or teammates) first, untying score and losing the game.

@WofWca WofWca force-pushed the fix-check-exit-rules-order branch from d4956d3 to a2c30aa Compare May 25, 2026 07:16
Compared to https://github.com/ec-/baseq3a/pull/73
this is a more general and robust fix,
also affecting railgun, shotgun, direct missile hits,
and telefrags.

Note that `G_RunFrame` still calls `CheckExitRules()` directly,
which probably makes sense, to keep things as is there.

Related:
- etlegacy/etlegacy#2051.
@WofWca WofWca force-pushed the fix-check-exit-rules-order branch from a2c30aa to 3327411 Compare May 28, 2026 15:55
@WofWca
Copy link
Copy Markdown
Contributor Author

WofWca commented May 28, 2026

I found a concrete "fragged each other at the same time" situation. Updated the comment, and added a video to the MR description.

@ec- ec- dismissed their stale review May 29, 2026 09:54

solved

@ec- ec- merged commit d7e1ec0 into ec-:master May 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants